﻿// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
//2021.11.17 by Sidney
//1.在ShadersBook基础上，分离场景光和人物光
//lightWorldPos计算可参考：https://blog.csdn.net/a958832776/article/details/104252892
//2.加上double Albedo map
//3.环境光，待完成
//4.内阴影，待完成
//固定环境光和反射可参考，只有一些关键字，球谐函数等等需自行理解：https://baddogzz.github.io/2020/03/25/Fix-Indirect-Lighting/
//环境反射贴图：											https://blog.csdn.net/qq_38572472/article/details/78922229
Shader "Unity Shaders Book/Common/Bumped Specular" {
	Properties {
		_Color ("Color Tint", Color) = (1, 1, 1, 1)
		_MainTex ("Main Tex", 2D) = "white" {}
		_BumpMap ("Normal Map", 2D) = "bump" {}
		_Specular ("Specular Color", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
		_AmbientIntensity("Ambient Intensity",Range(0,1))=0.3
		_SelfIntensity("_SelfIntensity",Float)=1
		_DetailAlbedoMap("Detailed Albedo",2D)="white"{}
		_DetailMaskVal("_DetailMaskVal",Range(0,1))=0.3
	}
	SubShader {
		Tags { "RenderType"="Opaque" "Queue"="Geometry"}
		
		Pass { 
			Tags { "LightMode"="ForwardBase" }
		
			CGPROGRAM
			
			#define selflit
			#pragma shader_feature_local_fragment _DETAIL_MULX2
			#pragma multi_compile_fwdbase	
			
			#pragma vertex vert
			#pragma fragment frag

			#include "AmbientSH.cginc"//自定义
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			
			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _BumpMap;
			float4 _BumpMap_ST;
			fixed4 _Specular;
			float _Gloss;
			sampler2D _DetailAlbedoMap;
			float4 _DetailAlbedoMap_ST;

			float4 _SelfMainLight;
			float4 _SelfDir;
			float _AmbientIntensity;
			float _SelfIntensity;
			float _DetailMaskVal;
			inline float4x4 GetRotateMatrix(float3 eularAngle)
		    {
		        eularAngle.xyz*=0.01745;  //UNITY_PI/180     角度转弧度
		        //X轴旋转
		        float angleX=eularAngle.x;
		        //Y轴旋转
		        float angleY=eularAngle.y;
		        //Z轴旋转
		        float angleZ=eularAngle.z;

		        float sinX=sin(angleX);
		        float cosX=cos(angleX);
		        float sinY=sin(angleY);
		        float cosY=cos(angleY);
		        float sinZ=sin(angleZ);
		        float cosZ=cos(angleZ);

		        float m00=cosY*cosZ;
		        float m01=-cosY*sinZ;
		        float m02=sinY;
		        float m03=0;
		        float m10=cosX*sinZ+sinX*sinY*cosZ;
		        float m11=cosX*cosZ-sinX*sinY*sinZ;
		        float m12=-sinX*cosY;
		        float m13=0;
		        float m20=sinX*sinZ-cosX*sinY*cosZ;
		        float m21=sinX*cosZ+cosX*sinY*sinZ;
		        float m22=cosX*cosY;
		        float m23=0;
		        float m30=0;
		        float m31=0;
		        float m32=0;
		        float m33=1;

		        float4x4 matrixRota=float4x4(m00,m01,m02,m03,m10,m11,m12,m13,m20,m21,m22,m23,m30,m31,m32,m33);
		        return matrixRota;
		    }
			// half DetailMask(float2 uv)
			// {
			// 	//sampler2D   _DetailMask;
			//     return tex2D (_DetailMask, uv).a;
			// }
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float4 uv : TEXCOORD0;
				float4 TtoW0 : TEXCOORD1;  
                float4 TtoW1 : TEXCOORD2;  
                float4 TtoW2 : TEXCOORD3;
				float3 lightDir :TEXCOORD4;
				SHADOW_COORDS(5)
				float4 uv2:TEXCOORD6;
				half4 ambientOrLightmapUV : TEXCOORD7;
			};
			
			v2f vert(a2v v) {
			 	v2f o;
				//对输出进行初始化
                UNITY_INITIALIZE_OUTPUT(v2f,o);
			 	o.pos = UnityObjectToClipPos(v.vertex);
			 
			 	o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
			 	o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;

				o.uv2.zw = TRANSFORM_TEX(v.texcoord, _DetailAlbedoMap);
				TANGENT_SPACE_ROTATION;
				
				float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;  
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);  
                fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);  
                fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 
                
                o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);  
                o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);  
                o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
				#ifndef selflit
  				float4x4 matrixRota=GetRotateMatrix(float3(0,0,0));
				#else
				float4x4 matrixRota=GetRotateMatrix(_SelfDir);
				float3 normalWorld = UnityObjectToWorldNormal(v.normal);
				o.ambientOrLightmapUV.rgb = ShadeSHPerVertexX(normalWorld,o.ambientOrLightmapUV.rgb);
				#endif
				
				float4 baseDir=float4(0,0,1,0);   //自身坐标系 z轴方向  Unity中的初始光源方向
				o.lightDir=-mul(matrixRota,baseDir); //旋转_EularAngle 之后的方向   作为光照方向（还需要-1*反方向）
				
  				TRANSFER_SHADOW(o);
			 	
			 	return o;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				
				float3 s_LightColor0 = _SelfMainLight;
				//float3 s_WorldSpaceLightPos0 = _SelfDir;
				float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
				#ifndef selflit
				fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
				#else
				// //fixed3 lightDir = normalize(s_WorldSpaceLightPos0.xyz);
				// fixed3 lightDir = normalize(i.lightDir);
				fixed3 lightDir = i.lightDir;
				#endif
				
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
				
				fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
				bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));

				fixed3 albedo = tex2D(_MainTex, i.uv.xy).rgb * _Color.rgb;
				
				half3 detailAlbedo = tex2D (_DetailAlbedoMap, i.uv2.zw).rgb;
				
				half mask = _DetailMaskVal;

    #if _DETAIL_MULX2
        albedo *= LerpWhiteTo (detailAlbedo * unity_ColorSpaceDouble.rgb, mask);
    #elif _DETAIL_MUL
        albedo *= LerpWhiteTo (detailAlbedo, mask);
    #elif _DETAIL_ADD
        albedo += detailAlbedo * mask;
    #elif _DETAIL_LERP
        albedo = lerp (albedo, detailAlbedo, mask);
    #endif
				
				#ifndef selflit
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				#else
				fixed3 ambient = _AmbientIntensity* albedo;//环境光，人物和场景分光，所以暂时不要
				//ambient+=i.ambientOrLightmapUV.rgb;//暂时不要，会有一层如雾气般的泛光，暂时无解
				#endif
				s_LightColor0.rgb *=_SelfIntensity;
			 	fixed3 diffuse = s_LightColor0.rgb * albedo * max(0, dot(bump, lightDir));
			 	
			 	fixed3 halfDir = normalize(lightDir + viewDir);
			 	fixed3 specular = s_LightColor0.rgb * _Specular.rgb * pow(max(0, dot(bump, halfDir)), _Gloss);
				
			
				UNITY_LIGHT_ATTENUATION(atten, i, worldPos);

				return fixed4(ambient + (diffuse + specular) * atten, 1.0);
				
			}
			
			ENDCG
		}
		
		Pass { 
			Tags { "LightMode"="ForwardAdd" }
			
			Blend One One
		
			CGPROGRAM
			
			#pragma multi_compile_fwdadd
			// Use the line below to add shadows for point and spot lights
//			#pragma multi_compile_fwdadd_fullshadows
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			
			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _BumpMap;
			float4 _BumpMap_ST;
			float _BumpScale;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float4 uv : TEXCOORD0;
				float4 TtoW0 : TEXCOORD1;  
                float4 TtoW1 : TEXCOORD2;  
                float4 TtoW2 : TEXCOORD3;
				SHADOW_COORDS(4)
			};
			
			v2f vert(a2v v) {
			 	v2f o;
			 	o.pos = UnityObjectToClipPos(v.vertex);
			 
			 	o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
			 	o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;

				float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;  
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);  
                fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);  
                fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 
	
  				o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
			  	o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
			  	o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);  
			 	
			 	TRANSFER_SHADOW(o);
			 	
			 	return o;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
				fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
				
				fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
				bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
				
				fixed3 albedo = tex2D(_MainTex, i.uv.xy).rgb * _Color.rgb;
				
			 	fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(bump, lightDir));
			 	
			 	fixed3 halfDir = normalize(lightDir + viewDir);
			 	fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(bump, halfDir)), _Gloss);
			
				UNITY_LIGHT_ATTENUATION(atten, i, worldPos);

				return fixed4((diffuse + specular) * atten, 1.0);
			}
			
			ENDCG
		}
	} 
	FallBack "Specular"
}
